package com.easy.system.controller;

import com.easy.system.model.BaseBean;
import com.easy.system.service.BizService;
import com.easy.system.util.MessageDto;
import com.easy.system.util.Pagination;
import com.easy.system.util.SqlUtils;
import com.easy.system.util.Utils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * User: sunguangzhu
 * Date: 13-7-6
 * Time: 下午12:23
 * To change this template use File | Settings | File Templates.
 */
@Controller
public class BaseController<T extends BaseBean> {

    /**
     * 模块名
     */
    private String moduleName;

    /**
     * 泛型的类
     */
    private Class<T> clazz;

    /**
     * 业务service 继承自baseService
     */
    private BizService<T> bizService;

    /**
     * set方法
     *
     * @param bizService
     */
    public void setBizService(BizService<T> bizService) {
        this.bizService = bizService;
    }

    /**
     * 默认的构造函数
     */
    public BaseController() {
    }

    /**
     * 含有参数的构造函数
     *
     * @param moduleName
     * @param clazz
     */
    public BaseController(String moduleName, Class<T> clazz) {
        this.moduleName = moduleName;
        this.clazz = clazz;
    }

    /**
     * 设置model
     *
     * @param model
     */
    protected void setModel(Model model) {
        model.addAttribute("moduleName", moduleName);
    }

    /**
     * 设置model
     *
     * @param model
     */
    protected void setModel(Model model, T entity) {
        model.addAttribute("moduleName", moduleName);
        model.addAttribute("bean", entity);
    }

    /**
     * 转到视图
     *
     * @param request
     * @return
     */
    protected String toView(HttpServletRequest request) {
        return request.getServletPath().replace(".do", "").replace("add", "input").replace("edit", "input");
    }

    /**
     * 根据id查找对象
     *
     * @param id
     * @return
     */
    protected T getEntity(Long id) {
        return (T) this.bizService.get(clazz, id);
    }

    /**
     * 更新实体
     *
     * @param entity
     */
    protected void updateEntity(T entity) {
        this.bizService.update(entity);
    }

    /**
     * 删除单个实体
     *
     * @param id
     */
    protected void deleteEntity(Long id) {
        this.bizService.delete(clazz, id);
    }

    /**
     * 批量删除
     *
     * @param ids
     * @return
     */
    protected Integer deleteEntitys(String ids) {
        return this.bizService.delete(clazz, ids);
    }

    /**
     * 设置messageDto
     *
     * @param messageDto
     * @param message
     */
    protected void setMessageDto(MessageDto messageDto, String message) {
        messageDto.setMessage(message);
    }

    /**
     * 参数绑定
     *
     * @param request
     * @param clazz
     * @return
     * @throws Exception
     */
    protected T injectObject(HttpServletRequest request, Class<T> clazz) throws Exception {
        Field[] fields = clazz.getDeclaredFields();
        Long id = null;
        T entity = null;
        if (!StringUtils.isBlank(request.getParameter("id"))) {
            id = Long.parseLong(request.getParameter("id"));
        }
        Object[] values = this.getParamValues(request, fields, clazz);
        Constructor[] constructors = clazz.getDeclaredConstructors();
        Constructor constructor = this.getParamsConstructor(constructors);
        try {
            entity = (T) constructor.newInstance(values);
            entity.setId(id);
        } catch (InstantiationException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (IllegalAccessException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (InvocationTargetException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        return entity;
    }

    /**
     * 辅助方法，用于获取参数对应的value
     *
     * @param request
     * @param fields
     * @param clazz
     * @return
     * @throws Exception
     */
    private Object[] getParamValues(HttpServletRequest request, Field[] fields, Class<T> clazz) throws Exception {
        List<Object> valueList = new ArrayList<Object>();
        Object[] values = null;
        for (Field field : fields) {
            String value = request.getParameter(field.getName());
            if (!StringUtils.isBlank(value)) {
                String fieldType = field.getType().getSimpleName();
                valueList.add(this.getRequestValue(field.getName(), fieldType, value, clazz));
            } else {
                valueList.add(null);
            }
        }
        if (valueList.size() == 0) {
            values = null;
        } else {
            values = valueList.toArray();
        }
        return values;  //To change body of created methods use File | Settings | File Templates.
    }

    /**
     * 辅助方法，用于获取request中的参数的value（含类型）
     *
     * @param fieldName
     * @param fieldType
     * @param value
     * @param clazz
     * @return
     * @throws Exception
     */
    private Object getRequestValue(String fieldName, String fieldType, String value, Class<T> clazz) throws Exception {
        Object result = null;
        if ("String".equals(fieldType)) {
            result = value;
        } else if ("Date".equals(fieldType)) {
            result = Utils.parseSqlDate(value);
        } else if ("Integer".equals(fieldType)
                || "int".equals(fieldType)) {
            result = Integer.parseInt(value);
        } else if ("Long".equalsIgnoreCase(fieldType)) {
            result = Long.parseLong(value);
        } else if ("Double".equalsIgnoreCase(fieldType)) {
            result = Double.parseDouble(value);
        } else if ("Boolean".equalsIgnoreCase(fieldType)) {
            result = Boolean.parseBoolean(value);
        } else {
            Object object = Class.forName((clazz.getDeclaredField(fieldName)).getType().getName()).newInstance();
            String name = clazz.getDeclaredField(fieldName).getName();
            Method method = object.getClass().getSuperclass().getDeclaredMethod("setId", Long.class);
            method.invoke(object, 1L);
            result = object;
        }
        return result;
    }

    /**
     * 辅助方法，用于获得含有参数的构造函数
     *
     * @param constructors
     * @return
     */
    private Constructor getParamsConstructor(Constructor[] constructors) {
        Constructor constructor = null;
        for (Constructor con : constructors) {
            if (con.getGenericParameterTypes().length > 0) {
                constructor = con;
                break;
            }
        }
        return constructor;
    }

    /**
     * 高级查询，获得实体查询列表
     *
     * @param request
     * @param pagination
     * @param allParams
     * @return
     * @throws Exception
     */
    protected List<T> getAdvanceQueryEntitys(HttpServletRequest request, Pagination pagination, String[] allParams) throws Exception {
        Map<String, Object[]> map = this.getAdvanceQueryPropParamsMap(request, allParams);
        Object[] properties = map.get("properties");
        Object[] params = map.get("params");
        return (List<T>) this.bizService.getAdvanceSearch(pagination, properties, params);
    }

    /**
     * 高级查询，获得实体总数
     *
     * @param request
     * @param allParams
     * @return
     * @throws Exception
     */
    protected Long getAdvanceQueryTotal(HttpServletRequest request, String[] allParams) throws Exception {
        Map<String, Object[]> map = this.getAdvanceQueryPropParamsMap(request, allParams);
        Object[] properties = map.get("properties");
        Object[] params = map.get("params");
        return this.bizService.getAdvanceSearchTotal(properties, params);
    }

    /**
     * 辅助方法，获得高级查询的参数和值
     *
     * @param request
     * @param allParams
     * @return
     * @throws Exception
     */
    protected Map<String, Object[]> getAdvanceQueryPropParamsMap(HttpServletRequest request, String[] allParams) throws Exception {
        Map<String, Object[]> map = new HashMap<String, Object[]>();
        List<String> propertiesList = new ArrayList<String>();
        List<Object> paramsList = new ArrayList<Object>();
        if (allParams == null) {
            Field[] fields = this.clazz.getDeclaredFields();
            for (Field field : fields) {
                //分类型
                String fieldName = field.getName();
                String value = request.getParameter(field.getName());
                if (!StringUtils.isBlank(value)) {
                    propertiesList.add(field.getName());
                    Object object = this.getRequestValue(fieldName, field.getType().getSimpleName(), value, clazz);
                    paramsList.add(object);
                }
            }
        } else {
            for (String string : allParams) {
                if (!StringUtils.isBlank(request.getParameter(string))) {
                    propertiesList.add(string);
                    Field field = clazz.getDeclaredField(string);
                    Object object = this.getRequestValue(field.getName(), field.getType().getName(), request.getParameter(string), clazz);
                    paramsList.add(object);
                }
            }
        }
        if (propertiesList.size() == 0) {
            map = null;
        } else {
            Object[] properties = propertiesList.toArray();
            Object[] params = paramsList.toArray();
            map.put("properties", properties);
            map.put("params", params);
        }
        return map;  //To change body of created methods use File | Settings | File Templates.
    }

    /**
     * 简单查询，获得查询实体列表
     *
     * @param property
     * @param searchValue
     * @param allProperties
     * @param pagination
     * @return
     */
    protected List<T> getSimpleQueryEntitys(String property, String searchValue, Object[] allProperties, Pagination pagination) throws Exception {
        Map<String, Object[]> map = this.getSimpleQueryPropPramsMap(property, searchValue, allProperties);
        Object[] properties = map.get("properties");
        Object[] params = map.get("params");
        return (List<T>) this.bizService.getSimpleSearch(pagination, properties, params);
    }

    /**
     * 简单查询，获得实体查询总数
     *
     * @param property
     * @param searchValue
     * @param allProperties
     * @return
     */
    protected Long getSimpleQueryTotal(String property, String searchValue, Object[] allProperties) throws Exception {
        Map<String, Object[]> map = this.getSimpleQueryPropPramsMap(property, searchValue, allProperties);
        Object[] properties = map.get("properties");
        Object[] params = map.get("params");
        return this.bizService.getSimpleSearchTotal(properties, params);
    }

    /**
     * 辅助方法，获得简单查询的参数和值
     *
     * @param property
     * @param searchValue
     * @param allProperties
     * @return
     */
    private Map<String, Object[]> getSimpleQueryPropPramsMap(String property, String searchValue, Object[] allProperties) throws Exception {
        Map<String, Object[]> map = new HashMap<String, Object[]>();
        Object[] properties = null;
        Object[] params = null;
        if (property.equals("all")) {
            if (!StringUtils.isBlank(searchValue)) {
                if (allProperties == null) {
                    //使用系统中自带的默认参数
                    Field[] fields = this.clazz.getDeclaredFields();
                    params = new Object[fields.length];
                    properties = new Object[fields.length];
                    for (int i = 0; i < fields.length; i++) {
                        properties[i] = fields[i].getName();
                        Object object = this.getRequestValue(fields[i].getName(), fields[i].getType().getSimpleName(), searchValue, clazz);
                        params[i] = object;
                    }
                } else {
                    params = new Object[allProperties.length];
                    for (int i = 0; i < params.length; i++) {
                        //考虑以后会增加更复杂的属性查询
                        Field field = clazz.getDeclaredField(allProperties[i].toString());
                        Object object = this.getRequestValue(field.getName(), field.getType().getSimpleName(), searchValue, clazz);
                        params[i] = SqlUtils.formateToLike(object.toString());
                    }
                }
            }
        } else {
            if (!StringUtils.isBlank(searchValue)) {
                properties = new Object[]{property};
                params = new Object[]{SqlUtils.formateToLike(searchValue)};
            }
        }
        map.put("properties", properties);
        map.put("params", params);
        return map;  //To change body of created methods use File | Settings | File Templates.
    }

    /**
     * 获得实体列表
     *
     * @param pagination
     * @return
     */
    protected List<T> getEntitys(Pagination pagination) {
        return this.bizService.find(pagination);
    }

    /**
     * 获得实体总数
     *
     * @return
     */
    protected Long getTotal() {
        return this.bizService.getTotal();
    }

    /**
     * 发送json到客户端
     *
     * @param response
     * @param jsonStr
     * @throws IOException
     */
    protected void writeToClient(HttpServletResponse response, String jsonStr) throws IOException {
        response.getWriter().write(jsonStr);
    }

}
